//Author: Bjorn Schobben

#include "Province.h"



Province::Province(const std::string& newName) : name(newName)
{
}

Province::Province(const Province& rhs): color(rhs.color), name(rhs.name)
{
	Copy(rhs);
}

Province::~Province()
{
	Clear();
}

void Province::Copy(const Province& rhs)
{
	std::list<Point*>::const_iterator pointIt;

	// Copy color
	SetColor(rhs.color);

	// Copy another province by inserting its points one-by-one into this province
	for(pointIt = rhs.points.begin(); pointIt != rhs.points.end(); ++pointIt)
	{
		const Point* point = *pointIt;

		InsertNewPoint(point->GetX(), point->GetY());
	}
}

void Province::Clear()
{
	// Clear all allocated provinces
	std::list<Point*>::iterator it;


	for(it = points.begin(); it != points.end(); ++it)
	{
		delete *it;
	}

	points.clear();
}

std::list<Point*>& Province::GetPoints()
{
	return points;
}


// Set the color of the province
void Province::SetColor(Color newColor)
{
		color = newColor;
} 

// Get province color
Color Province::GetColor() const
{
	return color;
}

// Get name
const std::string& Province::GetName() const
{
	return name;
}

// Clear neighbours list
void Province::ClearNeighbours()
{
	neighbours.clear();
}

// Insert a neighbour
void Province::InsertNeighbour(Province& province)
{
	neighbours.push_back(&province);
}

// Insert a point
Point* Province::InsertPoint(Point* point)
{
	points.push_back(point);

	return points.back();
}

// Insert a new empty point
Point* Province::InsertNewPoint(int x, int y)
{
	return InsertPoint(new Point(x, y));
}

// Insert a new point which copies contents from another point
Point* Province::InsertNewPoint(const Point& point)
{
	return InsertPoint(new Point(point));
}

// Set province name
void Province::SetName(const std::string& newName)
{
	name = newName;
}

// Compare if 2 provinces are equal
bool Province::operator==(const Province& rhs) const
{
	std::list<Point*>::const_iterator it;
	bool result = false;
	unsigned int commonPointCount = 0;
	

	// Two provinces are equal if they share the same points
	for(it = rhs.points.begin(); it != rhs.points.end(); ++it)
	{
		const Point* point = *it;

		// If this province does not contain a point of the other province
		if (!this->ContainsPoint(*point))
		{
			// Then they can't be same
			break;
		}
		else
		{
			commonPointCount++;
		}
	}

	// There was no point that this province did not contain of the other province
	// If they have the same amount of points, then they must be the same

	if (commonPointCount == points.size())
	{
		result = true;
	}

	return result;
}

// Test if a neighbour contains the test color
bool Province::NeighbourContainsColor(Color testColor) const
{
	std::list<Province*>::const_iterator it;
	bool colorFound = false;


	// Test if neighbours have this color already
	for(it = neighbours.begin(); it != neighbours.end(); ++it)
	{
		if((*it)->GetColor() == testColor)
		{
			colorFound = true;

			break;
		}
	}
	
	return colorFound;
}

// Test if this province contains a point
bool Province::ContainsPoint(const Point& point) const
{
	std::list<Point*>::const_iterator it;
	bool result = false;


	// Test if this province contains the point by checking each point in the province
	for(it = points.begin(); it != points.end(); ++it)
	{
		const Point *provincePoint = *it;
		if (*provincePoint == point)
		{
			result = true;

			break;
		}
	}
	

	return result;
}

// Accumulate unique colors to the colorTable
void Province::GetUniqueColors(std::list<Color>& colorTable) const
{
	bool found = false;
	std::list<Color>::iterator colorIt;

	// Only add real colors
	if (!GetColor().IsColor())
	{
		return;
	}
	
	// Test if color is already in the table
	for(colorIt = colorTable.begin(); colorIt != colorTable.end(); ++colorIt)
	{
		Color& color = *colorIt;

		if (color == GetColor())
		{
			found = true;
			break;
		}
	}

	// If not found, add it to the table
	if (!found)
	{
		colorTable.push_back(GetColor());
	}
}

// Get the amount of neighbours a province has
unsigned int Province::NeighbourCount() const
{
	return (unsigned int)neighbours.size();
}

// Get the amount of neighbours that have been colored
unsigned int Province::NeighbourColoredCount() const
{
	std::list<Province*>::const_iterator it;
	unsigned int neighbourColoredCount = 0;

	for(it = neighbours.begin(); it != neighbours.end(); ++it)
	{
		const Province *neighbour = *it;

		// If neighbour has a color, increase the counter
		if (neighbour->GetColor().IsColor())
		{
			neighbourColoredCount++;
		}
	}

	return neighbourColoredCount;
}

// Get next point, wrapping around if necessary
const Point* Province::WrapNextPoint(const std::list<Point*>& pointList, std::list<Point*>::const_iterator& it) const
{
	const Point* result = 0;
	std::list<Point*>::const_iterator next;

	// Pointers to the begin iterators
	const Point* begin = *pointList.begin();


	// Get next iterator
	next = it;
	++next;

	// Wrap around for this iterator
	if (next == pointList.end())
		result = begin;
	else
		result = *next;

	return result;
}

// Test if the passed province is neighbouring this province
bool Province::IsNeighbouring(const Province& province) const
{
	bool result = false;
	
	unsigned int pointCount = (unsigned int)points.size();
	unsigned int neighbourCount = (unsigned int)province.points.size();

	std::list<Point*>::const_iterator thisPointIt, neighbourPointIt, next;

	// Pointers to the begin iterators
	const Point* tbegin = *points.begin();
	const Point* nbegin = *province.points.begin();

	for(thisPointIt = points.begin(); thisPointIt != points.end(); ++thisPointIt)
	{
		const Point* tp0 = *thisPointIt;
		const Point* tp1 = WrapNextPoint(points, thisPointIt);

		// Make a line with previous and next point (assuming points are in clockwise order)
		LineSegment provinceLine(*tp0, *tp1);

		for(neighbourPointIt = province.points.begin(); neighbourPointIt != province.points.end(); ++neighbourPointIt)
		{
			const Point* np0 = *neighbourPointIt;
			const Point* np1 = WrapNextPoint(province.points, neighbourPointIt);

			LineSegment neighbourLine( *np0, *np1);

			// If they have overlapping line segments, then they must be neighbouring provinces
			if(provinceLine.OverlapsWith(neighbourLine))
			{
				result = true;
				break;
			}
		}
	}

	return result;
}


